#include "sdataset.h"

#include <algorithm>
#include <iterator>

extern "C" {
#include <hdf/mfhdf.h>
}

namespace sds {

  SDataset::SDataset(int fileId, int index) {
    datasetId = SDselect(fileId, index);
    char nameTmp[MAX_NC_NAME];
    SInteger dimTmp[MAX_VAR_DIMS];
    SInteger rankTmp;
    SInteger dataTypeTmp;
    int status = SDgetinfo(datasetId, nameTmp, &rankTmp, dimTmp,
			   &dataTypeTmp, &attributes);
    assert(status != FAIL);
    dataType = SDataTypeConverter::convert(dataTypeTmp);
    name = nameTmp;
    std::copy(dimTmp, dimTmp + rankTmp, std::back_inserter(size));
  }

  SDataset::~SDataset() {
    SDendaccess(datasetId);
  }

  SAttribute SDataset::getAttribute(const std::string& name) const {
    SInteger index = SDfindattr(datasetId, name.c_str());
    assert( index != FAIL);
    return getAttribute(index);    
  }
  

//   void SDataset::writeBuffer(const std::vector<SInteger>& start, 
// 			     const std::vector<SInteger>& size, 
// 			     const std::vector<SInteger>& stride, 
// 			     void* buffer) const {
//     SInteger startTmp[MAX_VAR_DIMS];
//     SInteger strideTmp[MAX_VAR_DIMS];
//     SInteger sizeTmp[MAX_VAR_DIMS];
//     assert(start.size() == getSize().size());
//     assert(stride.size() == getSize().size());
//     assert(size.size() == getSize().size());
//     std::copy(start.begin(), start.end(), startTmp);
//     std::copy(stride.begin(), stride.end(), strideTmp);
//     std::copy(size.begin(), size.end(), sizeTmp);
//     int status = SDwritedata(datasetId, startTmp, strideTmp, sizeTmp, buffer);
//     assert(status != FAIL);    
//   }

  int SDataset::Reader::getLength() const {
    return std::accumulate(size.begin(), size.end(), 
			   1, std::multiplies<int>());
  }  

  void SDataset::Reader::read(void *buffer) const {
    SInteger startTmp[MAX_VAR_DIMS];
    SInteger strideTmp[MAX_VAR_DIMS];
    SInteger sizeTmp[MAX_VAR_DIMS];
    assert(start.size() == dataset.getSize().size());
    assert(stride.size() == dataset.getSize().size());
    assert(size.size() == dataset.getSize().size());
    std::copy(start.begin(), start.end(), startTmp);
    std::copy(stride.begin(), stride.end(), strideTmp);
    std::copy(size.begin(), size.end(), sizeTmp);

    int status = SDreaddata(dataset.datasetId, startTmp, 
			    strideTmp, sizeTmp, buffer);
    assert(status != FAIL);   

  } 

  int SDataset::Writer::getLength() const {
    return std::accumulate(size.begin(), size.end(), 
			   1, std::multiplies<int>());
  }  

  void SDataset::Writer::write(void *buffer) const {
    SInteger startTmp[MAX_VAR_DIMS];
    SInteger strideTmp[MAX_VAR_DIMS];
    SInteger sizeTmp[MAX_VAR_DIMS];
    assert(start.size() == dataset.getSize().size());
    assert(stride.size() == dataset.getSize().size());
    assert(size.size() == dataset.getSize().size());
    std::copy(start.begin(), start.end(), startTmp);
    std::copy(stride.begin(), stride.end(), strideTmp);
    std::copy(size.begin(), size.end(), sizeTmp);

    int status = SDwritedata(dataset.datasetId, startTmp, 
			     strideTmp, sizeTmp, buffer);
    assert(status != FAIL);   
  } 

}
